/*

Miranda IM: the free IM client for Microsoft* Windows*

Copyright 2000-2009 Miranda ICQ/IM project,
all portions of this codebase are copyrighted to the people
listed in contributors.txt.

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/

#include "commonheaders.h"

#define LBN_MY_CHECK    0x1000
#define LBN_MY_RENAME   0x1001

#define WM_MY_REFRESH   (WM_USER+0x1000)
#define WM_MY_RENAME    (WM_USER+0x1001)

INT_PTR  Proto_EnumProtocols( WPARAM, LPARAM );
bool CheckProtocolOrder(void);

#define errMsg \
"WARNING! The account is going to be deleted. It means that all its \
settings, contacts and histories will be also erased.\n\n\
Are you absolutely sure?"

#define upgradeMsg \
"Your account was successfully upgraded. \
To activate it, restart of Miranda is needed.\n\n\
If you want to restart Miranda now, press Yes, if you want to upgrade another account, press No"

#define legacyMsg \
"This account uses legacy protocol plugin. \
Use Miranda IM options dialogs to change it's preferences."

#define welcomeMsg \
"Welcome to Miranda IM's account manager!\n \
Here you can set up your IM accounts.\n\n \
Select an account from the list on the left to see the available options. \
Alternatively, just click on the Plus sign underneath the list to set up a new IM account."

static HWND hAccMgr = NULL;

extern HANDLE hAccListChanged;

int UnloadPlugin( TCHAR* buf, int bufLen );

///////////////////////////////////////////////////////////////////////////////////////////////////
// Account edit form
// Gets PROTOACCOUNT* as a parameter, or NULL to edit a new one

typedef struct
{
        int action;
        PROTOACCOUNT* pa;
}
        AccFormDlgParam;

static INT_PTR CALLBACK AccFormDlgProc(HWND hwndDlg,UINT message, WPARAM wParam, LPARAM lParam)
{
        switch( message ) {
        case WM_INITDIALOG:
                TranslateDialogDefault(hwndDlg);
                {
                        PROTOCOLDESCRIPTOR** proto;
                        int protoCount, i, cnt = 0;
                        Proto_EnumProtocols(( WPARAM )&protoCount, ( LPARAM )&proto );
                        for ( i=0; i < protoCount; i++ ) {
                                PROTOCOLDESCRIPTOR* pd = proto[i];
                                if ( pd->type == PROTOTYPE_PROTOCOL && pd->cbSize == sizeof( *pd )) {
                                        SendDlgItemMessageA( hwndDlg, IDC_PROTOTYPECOMBO, CB_ADDSTRING, 0, (LPARAM)proto[i]->szName );
                                        ++cnt;
                                }
                        }
                        SendDlgItemMessage( hwndDlg, IDC_PROTOTYPECOMBO, CB_SETCURSEL, 0, 0 );
                        EnableWindow( GetDlgItem( hwndDlg, IDOK ), cnt != 0 );

                        SetWindowLongPtr( hwndDlg, GWLP_USERDATA, lParam );
                        AccFormDlgParam* param = ( AccFormDlgParam* )lParam;

                        if ( param->action == PRAC_ADDED ) // new account
                                SetWindowText( hwndDlg, TranslateT( "Create new account" ));
                        else {
                                TCHAR str[200];
                                if ( param->action == PRAC_CHANGED ) { // update
                                        EnableWindow( GetDlgItem( hwndDlg, IDC_PROTOTYPECOMBO ), FALSE );
                                        mir_sntprintf( str, SIZEOF(str), _T("%s: %s"), TranslateT( "Editing account" ), param->pa->tszAccountName );
                                }
                                else mir_sntprintf( str, SIZEOF(str), _T("%s: %s"), TranslateT( "Upgrading account" ), param->pa->tszAccountName );

                                SetWindowText( hwndDlg, str );
                                SetDlgItemText( hwndDlg, IDC_ACCNAME, param->pa->tszAccountName );
                                SetDlgItemTextA( hwndDlg, IDC_ACCINTERNALNAME, param->pa->szModuleName );
                                SendDlgItemMessageA( hwndDlg, IDC_PROTOTYPECOMBO, CB_SELECTSTRING, -1, (LPARAM)param->pa->szProtoName );

                                EnableWindow( GetDlgItem( hwndDlg, IDC_ACCINTERNALNAME ), FALSE );
                        }
                        SendDlgItemMessage( hwndDlg, IDC_ACCINTERNALNAME, EM_LIMITTEXT, 40, 0 );
                }
                return TRUE;

        case WM_COMMAND:
                switch( LOWORD(wParam)) {
                case IDOK:
                        {
                                AccFormDlgParam* param = ( AccFormDlgParam* )GetWindowLongPtr( hwndDlg, GWLP_USERDATA );
                                PROTOACCOUNT* pa = param->pa;

                                if ( param->action == PRAC_ADDED ) {
                                        char buf[200];
                                        GetDlgItemTextA( hwndDlg, IDC_ACCINTERNALNAME, buf, SIZEOF( buf ));
                                        rtrim( buf );
                                        if ( buf[0] ) {
                                                for (int i = 0; i < accounts.getCount(); ++i)
                                                        if (_stricmp(buf, accounts[i]->szModuleName) == 0)
                                                                return FALSE;
                                }       }

                                switch( param->action ) {
                                case PRAC_UPGRADED:
                                        {
                                                int idx;
                                                BOOL oldProto = pa->bOldProto;
                                                TCHAR szPlugin[MAX_PATH];
                                                mir_sntprintf(szPlugin, SIZEOF(szPlugin), _T("%s.dll"), StrConvT(pa->szProtoName));
                                                idx = accounts.getIndex(pa);
                                                UnloadAccount(pa, false, false);
                                                accounts.remove(idx);
                                                if (oldProto && UnloadPlugin(szPlugin, SIZEOF(szPlugin))) 
                                                {
                                                        TCHAR szNewName[MAX_PATH];
                                                        mir_sntprintf(szNewName, SIZEOF(szNewName), _T("%s~"), szPlugin);
                                                        MoveFile(szPlugin, szNewName);
                                                }
                                        }
                                        // fall through

                                case PRAC_ADDED:
                                        pa = (PROTOACCOUNT*)mir_calloc( sizeof( PROTOACCOUNT ));
                                        pa->cbSize = sizeof( PROTOACCOUNT );
                                        pa->bIsEnabled = TRUE;
                    pa->bIsVisible = TRUE;
                    
                                        pa->iOrder = accounts.getCount();
                                        pa->type = PROTOTYPE_PROTOCOL;
                                        break;
                                }
                                {
                                        TCHAR buf[256];
                                        GetDlgItemText( hwndDlg, IDC_ACCNAME, buf, SIZEOF( buf ));
                                        mir_free(pa->tszAccountName);
                                        pa->tszAccountName = mir_tstrdup( buf );
                                }
                                if ( param->action == PRAC_ADDED || param->action == PRAC_UPGRADED ) 
                {
                                        char buf[200];
                                        GetDlgItemTextA( hwndDlg, IDC_PROTOTYPECOMBO, buf, SIZEOF( buf ));
                                        pa->szProtoName = mir_strdup( buf );
                                        GetDlgItemTextA( hwndDlg, IDC_ACCINTERNALNAME, buf, SIZEOF( buf ));
                                        rtrim( buf );
                                        if ( buf[0] == 0 ) {
                                                int count = 1;
                                                for( ;; ) {
                                                        DBVARIANT dbv;
                                                        mir_snprintf( buf, SIZEOF(buf), "%s_%d", pa->szProtoName, count++ );
                                                        if ( DBGetContactSettingString( NULL, buf, "AM_BaseProto", &dbv ))
                                                                break;
                                                        DBFreeVariant( &dbv );
                                        }       }
                                        pa->szModuleName = mir_strdup( buf );

                                        if ( !pa->tszAccountName[0] ) {
                                                mir_free(pa->tszAccountName);
                                                pa->tszAccountName = mir_a2t(buf);
                                        }

                                        DBWriteContactSettingString( NULL, pa->szModuleName, "AM_BaseProto", pa->szProtoName );
                                        accounts.insert( pa );

                                        if ( ActivateAccount( pa )) {
                                                pa->ppro->OnEvent( EV_PROTO_ONLOAD, 0, 0 );
                                                if (!DBGetContactSettingByte(NULL, "CList", "MoveProtoMenus", FALSE))
                                                        pa->ppro->OnEvent( EV_PROTO_ONMENU, 0, 0 );
                                        }
                                        else pa->type = PROTOTYPE_DISPROTO;
                                }

                                WriteDbAccounts();
                                NotifyEventHooks( hAccListChanged, param->action, ( LPARAM )pa );

                                SendMessage( GetParent(hwndDlg), WM_MY_REFRESH, 0, 0 );
                        }

                        EndDialog( hwndDlg, TRUE );
                        break;

                case IDCANCEL:
                        EndDialog( hwndDlg, FALSE );
                        break;
                }
        }

        return FALSE;
}

///////////////////////////////////////////////////////////////////////////////////////////////////
// Accounts manager

struct TAccMgrData
{
        HFONT hfntTitle, hfntText;
        int titleHeight, textHeight;
        int selectedHeight, normalHeight;
        int iSelected;
};

struct TAccListData
{
        WNDPROC oldWndProc;
        int iItem;
        RECT rcCheck;

        HWND hwndEdit;
        WNDPROC oldEditProc;
};

static void sttClickButton(HWND hwndDlg, int idcButton)
{
        if (IsWindowEnabled(GetDlgItem(hwndDlg, idcButton)))
                PostMessage(hwndDlg, WM_COMMAND, MAKEWPARAM(idcButton, BN_CLICKED), (LPARAM)GetDlgItem(hwndDlg, idcButton));
}

static LRESULT CALLBACK sttEditSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
        switch (msg) 
    {
        case WM_KEYDOWN:
                switch (wParam) {
                case VK_RETURN:
                        DestroyWindow(hwnd);
                        return 0;

                case VK_ESCAPE:
            SetWindowLongPtr(hwnd, GWLP_WNDPROC, GetWindowLongPtr(hwnd, GWLP_USERDATA));
                        DestroyWindow(hwnd);
                        return 0;
                }
                break;

        case WM_GETDLGCODE:
                if (wParam == VK_RETURN || wParam == VK_ESCAPE)
                        return DLGC_WANTMESSAGE;
                break;

        case WM_KILLFOCUS:
                {
                        int length = GetWindowTextLength(hwnd) + 1;
                        TCHAR *str = ( TCHAR* )mir_alloc(sizeof(TCHAR) * length);
                        GetWindowText(hwnd, str, length);
                        SendMessage(GetParent(GetParent(hwnd)), WM_COMMAND, MAKEWPARAM(GetWindowLongPtr(GetParent(hwnd), GWL_ID), LBN_MY_RENAME), (LPARAM)str);
                }
                DestroyWindow(hwnd);
                return 0;
        }
        return CallWindowProc((WNDPROC)GetWindowLongPtr(hwnd, GWLP_USERDATA), hwnd, msg, wParam, lParam);
}

static LRESULT CALLBACK AccListWndProc(HWND hwnd,UINT msg, WPARAM wParam, LPARAM lParam)
{
        struct TAccListData *dat = (struct TAccListData *)GetWindowLongPtr(hwnd, GWLP_USERDATA);
        if ( !dat )
                return DefWindowProc(hwnd, msg, wParam, lParam);

        switch (msg) {
        case WM_LBUTTONDOWN:
                {
                        POINT pt = {LOWORD(lParam), HIWORD(lParam)};
                        int iItem = LOWORD(SendMessage(hwnd, LB_ITEMFROMPOINT, 0, lParam));
                        ListBox_GetItemRect(hwnd, iItem, &dat->rcCheck);

                        dat->rcCheck.right = dat->rcCheck.left + GetSystemMetrics(SM_CXSMICON) + 4;
                        dat->rcCheck.bottom = dat->rcCheck.top + GetSystemMetrics(SM_CYSMICON) + 4;
                        if (PtInRect(&dat->rcCheck, pt))
                                dat->iItem = iItem;
                        else
                                dat->iItem = -1;
                }
                break;

        case WM_LBUTTONUP:
                {
                        POINT pt = {LOWORD(lParam), HIWORD(lParam)};
                        if ((dat->iItem >= 0) && PtInRect(&dat->rcCheck, pt))
                                PostMessage(GetParent(hwnd), WM_COMMAND, MAKEWPARAM(GetWindowLongPtr(hwnd, GWL_ID), LBN_MY_CHECK), (LPARAM)dat->iItem);
                        dat->iItem = -1;
                }
                break;

        case WM_CHAR:
                if (wParam == ' ') {
                        int iItem = ListBox_GetCurSel(hwnd);
                        if (iItem >= 0)
                                PostMessage(GetParent(hwnd), WM_COMMAND, MAKEWPARAM(GetWindowLongPtr(hwnd, GWL_ID), LBN_MY_CHECK), (LPARAM)iItem);
                        return 0;
                }

                if (wParam == 10 /* enter */)
                        return 0;

                break;

        case WM_GETDLGCODE:
                if (wParam == VK_RETURN)
                        return DLGC_WANTMESSAGE;
                break;

        case WM_MY_RENAME:
                {
                        RECT rc;
                        struct TAccMgrData *parentDat = (struct TAccMgrData *)GetWindowLongPtr(GetParent(hwnd), GWLP_USERDATA);
                        PROTOACCOUNT *pa = (PROTOACCOUNT *)ListBox_GetItemData(hwnd, ListBox_GetCurSel(hwnd));
                        if (!pa || pa->bOldProto || pa->bDynDisabled)
                                return 0;

                        ListBox_GetItemRect(hwnd, ListBox_GetCurSel(hwnd), &rc);
                        rc.left += 2*GetSystemMetrics(SM_CXSMICON) + 4;
                        rc.bottom = rc.top + max(GetSystemMetrics(SM_CXSMICON), parentDat->titleHeight) + 4 - 1;
                        ++rc.top; --rc.right;

                        dat->hwndEdit = CreateWindow(_T("EDIT"), pa->tszAccountName, WS_CHILD|WS_BORDER|ES_AUTOHSCROLL, rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top, hwnd, NULL, hMirandaInst, NULL);
                        SetWindowLongPtr(dat->hwndEdit, GWLP_USERDATA, SetWindowLongPtr(dat->hwndEdit, GWLP_WNDPROC, (LONG_PTR)sttEditSubclassProc));
                        SendMessage(dat->hwndEdit, WM_SETFONT, (WPARAM)parentDat->hfntTitle, 0);
                        SendMessage(dat->hwndEdit, EM_SETMARGINS, EC_LEFTMARGIN|EC_RIGHTMARGIN|EC_USEFONTINFO, 0);
                        SendMessage(dat->hwndEdit, EM_SETSEL, 0, (LPARAM) (-1));
                        ShowWindow(dat->hwndEdit, SW_SHOW);
                }
                SetFocus(dat->hwndEdit);
                break;

        case WM_KEYDOWN:
                switch (wParam) {
                case VK_F2:
                        PostMessage(hwnd, WM_MY_RENAME, 0, 0);
                        return 0;

                case VK_INSERT:
                        sttClickButton(GetParent(hwnd), IDC_ADD);
                        return 0;

                case VK_DELETE:
                        sttClickButton(GetParent(hwnd), IDC_REMOVE);
                        return 0;

                case VK_RETURN:
                        if (GetAsyncKeyState(VK_CONTROL))
                                sttClickButton(GetParent(hwnd), IDC_EDIT);
                        else
                                sttClickButton(GetParent(hwnd), IDOK);
                        return 0;
                }
                break;
        }

        return CallWindowProc(dat->oldWndProc, hwnd, msg, wParam, lParam);
}

static void sttSubclassAccList(HWND hwnd, BOOL subclass)
{
        if (subclass) {
                struct TAccListData *dat = (struct TAccListData *)mir_alloc(sizeof(struct TAccListData));
                dat->iItem = -1;
                dat->oldWndProc = (WNDPROC)GetWindowLongPtr(hwnd, GWLP_WNDPROC);
                SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)dat);
                SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)AccListWndProc);
        }
        else {
                struct TAccListData *dat = (struct TAccListData *)GetWindowLongPtr(hwnd, GWLP_USERDATA);
                SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)dat->oldWndProc);
                SetWindowLongPtr(hwnd, GWLP_USERDATA, 0);
                mir_free(dat);
}       }

static void sttSelectItem(struct TAccMgrData *dat, HWND hwndList, int iItem)
{
        if ((dat->iSelected != iItem) && (dat->iSelected >= 0))
                ListBox_SetItemHeight(hwndList, dat->iSelected, dat->normalHeight);

        dat->iSelected = iItem;
        ListBox_SetItemHeight(hwndList, dat->iSelected, dat->selectedHeight);
        RedrawWindow(hwndList, NULL, NULL, RDW_INVALIDATE);
}

static void sttUpdateAccountInfo(HWND hwndDlg, struct TAccMgrData *dat)
{
        HWND hwndList = GetDlgItem(hwndDlg, IDC_ACCLIST);
        int curSel = ListBox_GetCurSel( hwndList );
        if ( curSel != LB_ERR ) {
                HWND hwnd;
                char svc[MAXMODULELABELLENGTH];

                PROTOACCOUNT *pa = (PROTOACCOUNT *)ListBox_GetItemData(hwndList, curSel);
                if ( pa ) {
                        EnableWindow( GetDlgItem( hwndDlg, IDC_UPGRADE ), pa->bOldProto || pa->bDynDisabled );
                        EnableWindow( GetDlgItem( hwndDlg, IDC_EDIT ), !pa->bOldProto && !pa->bDynDisabled );
                        EnableWindow( GetDlgItem( hwndDlg, IDC_REMOVE ), TRUE );
                        EnableWindow( GetDlgItem( hwndDlg, IDC_OPTIONS ), pa->ppro != 0 );

                        if ( dat->iSelected >= 0 ) {
                                PROTOACCOUNT *pa_old = (PROTOACCOUNT *)ListBox_GetItemData(hwndList, dat->iSelected);
                                if (pa_old && pa_old != pa && pa_old->hwndAccMgrUI)
                                        ShowWindow(pa_old->hwndAccMgrUI, SW_HIDE);
                        }

                        if ( pa->hwndAccMgrUI ) {
                                ShowWindow(GetDlgItem(hwndDlg, IDC_TXT_INFO), SW_HIDE);
                                ShowWindow(pa->hwndAccMgrUI, SW_SHOW);
                        }
                        else if ( !pa->ppro ) {
                                ShowWindow(GetDlgItem(hwndDlg, IDC_TXT_INFO), SW_SHOW);
                                SetWindowText(GetDlgItem(hwndDlg, IDC_TXT_INFO), TranslateT("Account is disabled. Please activate it to access options."));
                        }
                        else {
                                mir_snprintf(svc, SIZEOF(svc), "%s%s", pa->szModuleName, PS_CREATEACCMGRUI);
                                hwnd = (HWND)CallService(svc, 0, (LPARAM)hwndDlg);
                                if (hwnd && (hwnd != (HWND)CALLSERVICE_NOTFOUND)) {
                                        RECT rc;

                                        ShowWindow(GetDlgItem(hwndDlg, IDC_TXT_INFO), SW_HIDE);

                                        GetWindowRect(GetDlgItem(hwndDlg, IDC_TXT_INFO), &rc);
                                        MapWindowPoints(NULL, hwndDlg, (LPPOINT)&rc, 2);
                                        SetWindowPos(hwnd, hwndList, rc.left, rc.top, 0, 0, SWP_NOSIZE|SWP_SHOWWINDOW);

                                        pa->hwndAccMgrUI = hwnd;
                                }
                                else {
                                        ShowWindow(GetDlgItem(hwndDlg, IDC_TXT_INFO), SW_SHOW);
                                        SetWindowText(GetDlgItem(hwndDlg, IDC_TXT_INFO), TranslateT(legacyMsg));
                        }       }
                        return;
        }       }
        
        EnableWindow( GetDlgItem( hwndDlg, IDC_UPGRADE ), FALSE );
        EnableWindow( GetDlgItem( hwndDlg, IDC_EDIT ), FALSE );
        EnableWindow( GetDlgItem( hwndDlg, IDC_REMOVE ), FALSE );
        EnableWindow( GetDlgItem( hwndDlg, IDC_OPTIONS ), FALSE );

        ShowWindow(GetDlgItem(hwndDlg, IDC_TXT_INFO), SW_SHOW);
        SetWindowText(GetDlgItem(hwndDlg, IDC_TXT_INFO), TranslateT(welcomeMsg));
}

INT_PTR CALLBACK AccMgrDlgProc(HWND hwndDlg,UINT message, WPARAM wParam, LPARAM lParam)
{
        struct TAccMgrData *dat = (struct TAccMgrData *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);

        switch(message) {
        case WM_INITDIALOG:
                {
                        TAccMgrData *dat = (TAccMgrData *)mir_alloc(sizeof(TAccMgrData));
                        SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)dat);

                        TranslateDialogDefault(hwndDlg);
                        Window_SetIcon_IcoLib( hwndDlg, SKINICON_OTHER_ACCMGR );

                        Button_SetIcon_IcoLib(hwndDlg, IDC_ADD, SKINICON_OTHER_ADDCONTACT, LPGEN("New account"));
                        Button_SetIcon_IcoLib(hwndDlg, IDC_EDIT, SKINICON_OTHER_RENAME, LPGEN("Edit"));
                        Button_SetIcon_IcoLib(hwndDlg, IDC_REMOVE, SKINICON_OTHER_DELETE, LPGEN("Remove account"));
                        Button_SetIcon_IcoLib(hwndDlg, IDC_OPTIONS, SKINICON_OTHER_OPTIONS, LPGEN( "Configure..."));
                        Button_SetIcon_IcoLib(hwndDlg, IDC_UPGRADE, SKINICON_OTHER_ACCMGR, LPGEN("Upgrade account"));

                        EnableWindow(GetDlgItem(hwndDlg, IDC_EDIT), FALSE);
                        EnableWindow(GetDlgItem(hwndDlg, IDC_REMOVE), FALSE);
                        EnableWindow(GetDlgItem(hwndDlg, IDC_OPTIONS), FALSE);
                        EnableWindow(GetDlgItem(hwndDlg, IDC_UPGRADE), FALSE);

                        {
                                LOGFONT lf;
                                HDC hdc;
                                HFONT hfnt;
                                TEXTMETRIC tm;

                                GetObject((HFONT)SendMessage(hwndDlg, WM_GETFONT, 0, 0), sizeof(lf), &lf);
                                dat->hfntText = CreateFontIndirect(&lf);

                                GetObject((HFONT)SendMessage(hwndDlg, WM_GETFONT, 0, 0), sizeof(lf), &lf);
                                lf.lfWeight = FW_BOLD;
                                dat->hfntTitle = CreateFontIndirect(&lf);

                                hdc = GetDC(hwndDlg);
                                hfnt = ( HFONT )SelectObject(hdc, dat->hfntTitle);
                                GetTextMetrics(hdc, &tm);
                                dat->titleHeight = tm.tmHeight;
                                SelectObject(hdc, dat->hfntText);
                                GetTextMetrics(hdc, &tm);
                                dat->textHeight = tm.tmHeight;
                                SelectObject(hdc, hfnt);
                                ReleaseDC(hwndDlg, hdc);

                                dat->normalHeight = 4 + max(dat->titleHeight, GetSystemMetrics(SM_CYSMICON));
                                dat->selectedHeight = dat->normalHeight + 4 + 2 * dat->textHeight;

                                SendDlgItemMessage(hwndDlg, IDC_NAME, WM_SETFONT, (WPARAM)dat->hfntTitle, 0);
                                SendDlgItemMessage(hwndDlg, IDC_TXT_ACCOUNT, WM_SETFONT, (WPARAM)dat->hfntTitle, 0);
                                SendDlgItemMessage(hwndDlg, IDC_TXT_ADDITIONAL, WM_SETFONT, (WPARAM)dat->hfntTitle, 0);
                        }

                        dat->iSelected = -1;
                        sttSubclassAccList(GetDlgItem(hwndDlg, IDC_ACCLIST), TRUE);
                        SendMessage( hwndDlg, WM_MY_REFRESH, 0, 0 );

                        Utils_RestoreWindowPositionNoSize(hwndDlg, NULL, "AccMgr", "");
                }
                return TRUE;

        case WM_CTLCOLORSTATIC:
                switch ( GetDlgCtrlID(( HWND )lParam )) {
                case IDC_WHITERECT:
                case IDC_NAME:
                        SetBkColor(( HDC )wParam, GetSysColor( COLOR_WINDOW ));
                        return ( INT_PTR )GetSysColorBrush( COLOR_WINDOW );
                }
                break;

        case WM_MEASUREITEM:
                {
                        LPMEASUREITEMSTRUCT lps = (LPMEASUREITEMSTRUCT)lParam;
                        PROTOACCOUNT *acc = (PROTOACCOUNT *)lps->itemData;

                        if ((lps->CtlID != IDC_ACCLIST) || !acc)
                                break;

                        lps->itemWidth = 10;
                        lps->itemHeight = dat->normalHeight;
                }
                return TRUE;

        case WM_DRAWITEM:
                {
                        int tmp, size, length;
                        TCHAR *text;
                        HICON hIcon;
                        HBRUSH hbrBack;
                        SIZE sz;

                        int cxIcon = GetSystemMetrics(SM_CXSMICON);
                        int cyIcon = GetSystemMetrics(SM_CYSMICON);

                        LPDRAWITEMSTRUCT lps = (LPDRAWITEMSTRUCT)lParam;
                        PROTOACCOUNT *acc = (PROTOACCOUNT *)lps->itemData;

                        if ((lps->CtlID != IDC_ACCLIST) || (lps->itemID == -1) || !acc)
                                break;

                        SetBkMode(lps->hDC, TRANSPARENT);
                        if (lps->itemState & ODS_SELECTED) {
                                hbrBack = GetSysColorBrush(COLOR_HIGHLIGHT);
                                SetTextColor(lps->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT));
                        }
                        else {
                                hbrBack = GetSysColorBrush(COLOR_WINDOW);
                                SetTextColor(lps->hDC, GetSysColor(COLOR_WINDOWTEXT));
                        }
                        FillRect(lps->hDC, &lps->rcItem, hbrBack);

                        lps->rcItem.left += 2;
                        lps->rcItem.top += 2;
                        lps->rcItem.bottom -= 2;

                        if ( acc->bOldProto )
                                tmp = SKINICON_OTHER_ON;
                        else if ( acc->bDynDisabled )
                                tmp = SKINICON_OTHER_OFF;
                        else
                                tmp = acc->bIsEnabled ? SKINICON_OTHER_TICK : SKINICON_OTHER_NOTICK;

                        hIcon = LoadSkinnedIcon(tmp);
                        DrawIconEx(lps->hDC, lps->rcItem.left, lps->rcItem.top, hIcon, cxIcon, cyIcon, 0, hbrBack, DI_NORMAL);
                        IconLib_ReleaseIcon(hIcon, 0);

                        lps->rcItem.left += cxIcon + 2;

                        if (acc->ppro) {
                                hIcon = acc->ppro->GetIcon( PLI_PROTOCOL | PLIF_SMALL );
                                DrawIconEx(lps->hDC, lps->rcItem.left, lps->rcItem.top, hIcon, cxIcon, cyIcon, 0, hbrBack, DI_NORMAL);
                                DestroyIcon(hIcon);
                        }
                        lps->rcItem.left += cxIcon + 2;

                        length = SendDlgItemMessage(hwndDlg, IDC_ACCLIST, LB_GETTEXTLEN, lps->itemID, 0);
                        size = max(length+1, 256);
                        text = (TCHAR *)_alloca(sizeof(TCHAR) * size);
                        SendDlgItemMessage(hwndDlg, IDC_ACCLIST, LB_GETTEXT, lps->itemID, (LPARAM)text);

                        SelectObject(lps->hDC, dat->hfntTitle);
                        tmp = lps->rcItem.bottom;
                        lps->rcItem.bottom = lps->rcItem.top + max(cyIcon, dat->titleHeight);
                        DrawText(lps->hDC, text, -1, &lps->rcItem, DT_LEFT|DT_NOPREFIX|DT_SINGLELINE|DT_END_ELLIPSIS|DT_VCENTER);
                        lps->rcItem.bottom = tmp;
                        GetTextExtentPoint32(lps->hDC, text, length, &sz);
                        lps->rcItem.top += max(cxIcon, sz.cy) + 2;

                        if (lps->itemID == (unsigned)dat->iSelected) {
                                SelectObject(lps->hDC, dat->hfntText);
                                mir_sntprintf(text, size, _T("%s: ") _T(TCHAR_STR_PARAM), TranslateT("Protocol"), acc->szProtoName);
                                length = lstrlen(text);
                                DrawText(lps->hDC, text, -1, &lps->rcItem, DT_LEFT|DT_NOPREFIX|DT_SINGLELINE|DT_END_ELLIPSIS);
                                GetTextExtentPoint32(lps->hDC, text, length, &sz);
                                lps->rcItem.top += sz.cy + 2;

                                if (acc->ppro && Proto_IsProtocolLoaded(acc->szProtoName)) {
                                        char *szIdName;
                                        TCHAR *tszIdName;
                                        CONTACTINFO ci = { 0 };

                                        szIdName = (char *)acc->ppro->GetCaps( PFLAG_UNIQUEIDTEXT, 0 );
                                        tszIdName = szIdName ? mir_a2t(szIdName) : mir_tstrdup(TranslateT("Account ID"));
                                        
                                        ci.cbSize = sizeof(ci);
                                        ci.hContact = NULL;
                                        ci.szProto = acc->szModuleName;
                                        ci.dwFlag = CNF_UNIQUEID | CNF_TCHAR;
                                        if ( !CallService(MS_CONTACT_GETCONTACTINFO, 0, (LPARAM) & ci)) {
                                                switch (ci.type) {
                                                case CNFT_ASCIIZ:
                                                        mir_sntprintf( text, size, _T("%s: %s"), tszIdName, ci.pszVal );
                                                        mir_free(ci.pszVal);
                                                        break;
                                                case CNFT_DWORD:
                                                        mir_sntprintf( text, size, _T("%s: %d"), tszIdName, ci.dVal );
                                                        break;
                                                }
                                        }
                                        else mir_sntprintf(text, size, _T("%s: %s"), tszIdName, TranslateT("<unknown>"));
                                        mir_free(tszIdName);
                                }
                                else mir_sntprintf(text, size, TranslateT("Protocol is not loaded."));

                                length = lstrlen(text);
                                DrawText(lps->hDC, text, -1, &lps->rcItem, DT_LEFT|DT_NOPREFIX|DT_SINGLELINE|DT_END_ELLIPSIS);
                                GetTextExtentPoint32(lps->hDC, text, length, &sz);
                                lps->rcItem.top += sz.cy + 2;
                }       }
                return TRUE;

        case WM_MY_REFRESH:
                {
                        HWND hList = GetDlgItem(hwndDlg, IDC_ACCLIST);
                        int i = ListBox_GetCurSel(hList);
                        PROTOACCOUNT *acc = (i == LB_ERR) ? NULL : (PROTOACCOUNT *)ListBox_GetItemData(hList, i);

                        dat->iSelected = -1;
                        SendMessage( hList, LB_RESETCONTENT, 0, 0 );
                        for (i = 0; i < accounts.getCount(); ++i) {
                                int iItem = SendMessage(hList, LB_ADDSTRING, 0, (LPARAM)accounts[i]->tszAccountName);
                                SendMessage(hList, LB_SETITEMDATA, iItem, (LPARAM)accounts[i]);

                                if (accounts[i] == acc)
                                        ListBox_SetCurSel(hList, iItem);
                        }

                        dat->iSelected = ListBox_GetCurSel(hList); // -1 if error => nothing selected in our case
                        if (dat->iSelected >= 0)
                                sttSelectItem(dat, hList, dat->iSelected);
                        else if (acc && acc->hwndAccMgrUI)
                                ShowWindow(acc->hwndAccMgrUI, SW_HIDE);

                        sttUpdateAccountInfo(hwndDlg, dat);
                }
                break;

        case WM_CONTEXTMENU:
                if ( GetWindowLongPtr(( HWND )wParam, GWL_ID ) == IDC_ACCLIST ) {
                        HWND hwndList = GetDlgItem( hwndDlg, IDC_ACCLIST );
                        POINT pt = { (signed short)LOWORD( lParam ), (signed short)HIWORD( lParam ) };
                        int iItem = ListBox_GetCurSel( hwndList );

                        if (( pt.x == -1 ) && ( pt.y == -1 )) {
                                if (iItem != LB_ERR) {
                                        RECT rc;
                                        ListBox_GetItemRect( hwndList, iItem, &rc );
                                        pt.x = rc.left + GetSystemMetrics(SM_CXSMICON) + 4;
                                        pt.y = rc.top + 4 + max(GetSystemMetrics(SM_CXSMICON), dat->titleHeight);
                                        ClientToScreen( hwndList, &pt );
                                }
                        }
                        else {
                                // menu was activated with mouse => find item under cursor & set focus to our control.
                                POINT ptItem = pt;
                                ScreenToClient( hwndList, &ptItem );
                                iItem = (short)LOWORD(SendMessage(hwndList, LB_ITEMFROMPOINT, 0, MAKELPARAM(ptItem.x, ptItem.y)));
                                if (iItem != LB_ERR) 
                {
                                    ListBox_SetCurSel(hwndList, iItem);
                    sttUpdateAccountInfo(hwndDlg, dat);
                                    sttSelectItem(dat, hwndList, iItem);
                                    SetFocus(hwndList);
                }
                        }

                        if ( iItem != LB_ERR ) {
                                PROTOACCOUNT* pa = (PROTOACCOUNT*)ListBox_GetItemData(hwndList, iItem);
                                HMENU hMenu = CreatePopupMenu();
                                if ( !pa->bOldProto && !pa->bDynDisabled )
                                        AppendMenu(hMenu, MF_STRING, 1, TranslateT("Rename"));

                                AppendMenu(hMenu, MF_STRING, 3, TranslateT("Delete"));

                                if ( Proto_IsAccountEnabled( pa ))
                                        AppendMenu(hMenu, MF_STRING, 4, TranslateT("Configure"));

                                if ( pa->bOldProto || pa->bDynDisabled )
                                        AppendMenu(hMenu, MF_STRING, 5, TranslateT("Upgrade"));

                                AppendMenu(hMenu, MF_SEPARATOR, 0, NULL);
                                AppendMenu(hMenu, MF_STRING, 0, TranslateT("Cancel"));
                                switch (TrackPopupMenu( hMenu, TPM_RETURNCMD, pt.x, pt.y, 0, hwndDlg, NULL )) {
                                case 1:
                                        PostMessage(hwndList, WM_MY_RENAME, 0, 0);
                                        break;

                                case 2:
                                        sttClickButton(hwndDlg, IDC_EDIT);
                                        break;

                                case 3:
                                        sttClickButton(hwndDlg, IDC_REMOVE);
                                        break;

                                case 4:
                                        sttClickButton(hwndDlg, IDC_OPTIONS);
                                        break;

                                case 5:
                                        sttClickButton(hwndDlg, IDC_UPGRADE);
                                        break;
                                }
                                DestroyMenu( hMenu );
                        }       
                }
                break;

        case WM_COMMAND:
                switch( LOWORD(wParam)) {
                case IDC_ACCLIST:
                        {
                                HWND hwndList = GetDlgItem(hwndDlg, IDC_ACCLIST);
                                switch (HIWORD(wParam)) {
                                case LBN_SELCHANGE:
                                        sttUpdateAccountInfo(hwndDlg, dat);
                                        sttSelectItem(dat, hwndList, ListBox_GetCurSel(hwndList));
                                        SetFocus(hwndList);
                                        break;

                                case LBN_DBLCLK:
                                        PostMessage(hwndList, WM_MY_RENAME, 0, 0);
                                        break;

                                case LBN_MY_CHECK:
                                        {
                                                PROTOACCOUNT *pa = (PROTOACCOUNT *)ListBox_GetItemData(hwndList, lParam);
                                                if ( pa ) {
                                                        if ( pa->bOldProto || pa->bDynDisabled)
                                                                break;

                                                        pa->bIsEnabled = !pa->bIsEnabled;
                                                        if ( pa->bIsEnabled ) {
                                                                if ( ActivateAccount( pa )) {
                                                                        pa->ppro->OnEvent( EV_PROTO_ONLOAD, 0, 0 );
                                                                        if (!DBGetContactSettingByte(NULL, "CList", "MoveProtoMenus", FALSE))
                                                                                pa->ppro->OnEvent( EV_PROTO_ONMENU, 0, 0 );
                                                                }
                                                                else pa->type = PROTOTYPE_DISPROTO;
                                                        }
                                                        else {
                                                                DWORD dwStatus = CallProtoService(pa->szModuleName, PS_GETSTATUS, 0, 0);
                                                                if (dwStatus >= ID_STATUS_ONLINE) {
                                                                        if (IDCANCEL == ::MessageBox(hwndDlg,
                                                                                                  TranslateT("Account is online. Disable account?"),
                                                                                                                           TranslateT("Accounts"), MB_OKCANCEL)) {
                                                                                pa->bIsEnabled = 1;     //stay enabled
                                                                        }
                                                                }

                                                                if ( !pa->bIsEnabled )
                                                                        DeactivateAccount( pa, true, false );
                                                        }

                                                        WriteDbAccounts();
                                                        NotifyEventHooks( hAccListChanged, PRAC_CHECKED, ( LPARAM )pa );
                                                        sttUpdateAccountInfo(hwndDlg, dat);
                                                        RedrawWindow(hwndList, NULL, NULL, RDW_INVALIDATE);
                                        }       }
                                        break;

                                case LBN_MY_RENAME:
                                        {
                                                int iItem = ListBox_GetCurSel(hwndList);
                                                PROTOACCOUNT *pa = (PROTOACCOUNT *)ListBox_GetItemData(hwndList, iItem);
                                                if ( pa ) {
                                                        mir_free(pa->tszAccountName);
                                                        pa->tszAccountName = (TCHAR*)lParam;
                                                        WriteDbAccounts();
                                                        NotifyEventHooks(hAccListChanged, PRAC_CHANGED, (LPARAM)pa);

                                                        ListBox_DeleteString(hwndList, iItem);
                                                        iItem = ListBox_AddString(hwndList, pa->tszAccountName);
                                                        ListBox_SetItemData(hwndList, iItem, (LPARAM)pa);
                                                        ListBox_SetCurSel(hwndList, iItem);

                                                        sttSelectItem(dat, hwndList, iItem);

                                                        RedrawWindow(hwndList, NULL, NULL, RDW_INVALIDATE);
                                                }
                                                else mir_free((TCHAR*)lParam);
                                        }
                                        break;
                        }       }
                        break;

                case IDC_ADD:
                        {
                                AccFormDlgParam param = { PRAC_ADDED, NULL };
                                if ( IDOK == DialogBoxParam( hMirandaInst, MAKEINTRESOURCE(IDD_ACCFORM), hwndDlg, AccFormDlgProc, (LPARAM)&param ))
                                        SendMessage( hwndDlg, WM_MY_REFRESH, 0, 0 );
                        }
                        break;

                case IDC_EDIT:
                        {
                                HWND hList = GetDlgItem( hwndDlg, IDC_ACCLIST );
                                int idx = ListBox_GetCurSel( hList );
                                if ( idx != -1 )
                                        PostMessage(hList, WM_MY_RENAME, 0, 0);
                        }
                        break;

                case IDC_REMOVE:
                        {
                                HWND hList = GetDlgItem( hwndDlg, IDC_ACCLIST );
                                int idx = ListBox_GetCurSel( hList );
                                if ( idx != -1 ) {
                                        PROTOACCOUNT* pa = ( PROTOACCOUNT* )ListBox_GetItemData( hList, idx );
                                        TCHAR buf[ 200 ];
                                        mir_sntprintf( buf, SIZEOF(buf), TranslateT( "Account %s is being deleted" ), pa->tszAccountName );
                                        if (pa->bOldProto) {
                                                MessageBox( NULL, TranslateT( "You need to disable plugin to delete this account" ), buf,
                                                        MB_ICONERROR | MB_OK );
                                                break;
                                        }
                                        if ( IDYES == MessageBox( NULL, TranslateT( errMsg ), buf, MB_ICONSTOP | MB_DEFBUTTON2 | MB_YESNO )) {
                                                // lock controls to avoid changes during remove process
                                                ListBox_SetCurSel( hList, -1 );
                                                sttUpdateAccountInfo( hwndDlg, dat );
                                                EnableWindow( hList, FALSE );
                                                EnableWindow( GetDlgItem(hwndDlg, IDC_ADD), FALSE );

                                                ListBox_SetItemData( hList, idx, 0 );

                                                accounts.remove( pa );

                                                CheckProtocolOrder();

                                                WriteDbAccounts();
                                                NotifyEventHooks( hAccListChanged, PRAC_REMOVED, ( LPARAM )pa );

                                                UnloadAccount( pa, true, true );
                                                SendMessage( hwndDlg, WM_MY_REFRESH, 0, 0 );

                                                EnableWindow( hList, TRUE );
                                                EnableWindow( GetDlgItem(hwndDlg, IDC_ADD), TRUE );
                        }       }       }
                        break;

                case IDC_OPTIONS:
                        {
                                HWND hList = GetDlgItem( hwndDlg, IDC_ACCLIST );
                                int idx = ListBox_GetCurSel( hList );
                                if ( idx != -1 ) {
                                        PROTOACCOUNT* pa = ( PROTOACCOUNT* )ListBox_GetItemData( hList, idx );
                                        if ( pa->bOldProto ) {
                                                OPENOPTIONSDIALOG ood;
                                                ood.cbSize = sizeof(ood);
                                                ood.pszGroup = "Network";
                                                ood.pszPage = pa->szModuleName;
                                                ood.pszTab = NULL;
                                                CallService( MS_OPT_OPENOPTIONS, 0, (LPARAM)&ood );
                                        }
                                        else OpenAccountOptions( pa );
                        }       }
                        break;

                case IDC_UPGRADE:
                        {
                                HWND hList = GetDlgItem( hwndDlg, IDC_ACCLIST );
                                int idx = ListBox_GetCurSel( hList );
                                if ( idx != -1 ) {
                                        AccFormDlgParam param = { PRAC_UPGRADED, ( PROTOACCOUNT* )ListBox_GetItemData( hList, idx ) };
                                        DialogBoxParam( hMirandaInst, MAKEINTRESOURCE(IDD_ACCFORM), hwndDlg, AccFormDlgProc, (LPARAM)&param );
                        }       }
                        break;

                case IDC_LNK_NETWORK:
                        {
                                PSHNOTIFY pshn = {0};
                                pshn.hdr.code = PSN_APPLY;
                                pshn.hdr.hwndFrom = hwndDlg;
                                SendMessage(hwndDlg, WM_NOTIFY, 0, (LPARAM)&pshn);

                                OPENOPTIONSDIALOG ood = {0};
                                ood.cbSize = sizeof(ood);
                                ood.pszPage = "Network";
                                CallService( MS_OPT_OPENOPTIONS, 0, (LPARAM)&ood );
                                break;
                        }

                case IDC_LNK_ADDONS:
                        CallService(MS_UTILS_OPENURL, TRUE, (LPARAM)"http://addons.miranda-im.org/");
                        break;

                case IDOK:
                        {
                                PSHNOTIFY pshn = {0};
                                pshn.hdr.code = PSN_APPLY;
                                pshn.hdr.hwndFrom = hwndDlg;
                                SendMessage(hwndDlg, WM_NOTIFY, 0, (LPARAM)&pshn);
                                DestroyWindow(hwndDlg);
                                break;
                        }

                case IDCANCEL:
                        {
                                PSHNOTIFY pshn = {0};
                                pshn.hdr.code = PSN_RESET;
                                pshn.hdr.hwndFrom = hwndDlg;
                                SendMessage(hwndDlg, WM_NOTIFY, 0, (LPARAM)&pshn);
                                DestroyWindow(hwndDlg);
                                break;
                        }
                }
        case PSM_CHANGED:
                {
                        HWND hList = GetDlgItem( hwndDlg, IDC_ACCLIST );
                        int idx = ListBox_GetCurSel( hList );
                        if ( idx != -1 ) {
                                PROTOACCOUNT *acc = (PROTOACCOUNT *)ListBox_GetItemData(hList, idx);
                                if (acc)
                                {
                                        acc->bAccMgrUIChanged = TRUE;
                                        SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
                                }
                        }
                        break;
                }
        case WM_NOTIFY:
                switch(((LPNMHDR)lParam)->idFrom) {
                case 0:
                        switch (((LPNMHDR)lParam)->code) {
                                case PSN_APPLY:
                                {       
                                        int i;
                                        PSHNOTIFY pshn = {0};
                                        pshn.hdr.code = PSN_APPLY;
                                        for (i = 0; i < accounts.getCount(); ++i) {
                                                if ( accounts[i]->hwndAccMgrUI && accounts[i]->bAccMgrUIChanged ) {
                                                        pshn.hdr.hwndFrom = accounts[i]->hwndAccMgrUI;
                                                        SendMessage(accounts[i]->hwndAccMgrUI, WM_NOTIFY, 0, (LPARAM)&pshn);
                                                        accounts[i]->bAccMgrUIChanged = FALSE;
                                        }       }
                                        return TRUE;
                                }
                                case PSN_RESET:
                                {       
                                        int i;
                                        PSHNOTIFY pshn = {0};
                                        pshn.hdr.code = PSN_RESET;
                                        for (i = 0; i < accounts.getCount(); ++i) {
                                                if ( accounts[i]->hwndAccMgrUI && accounts[i]->bAccMgrUIChanged ) {
                                                        pshn.hdr.hwndFrom = accounts[i]->hwndAccMgrUI;
                                                        SendMessage(accounts[i]->hwndAccMgrUI, WM_NOTIFY, 0, (LPARAM)&pshn);
                                                        accounts[i]->bAccMgrUIChanged = FALSE;
                                        }       }
                                        return TRUE;
                                }
                        }
                        break;
                }
                break;
        case WM_DESTROY:
                {
                        for (int i = 0; i < accounts.getCount(); ++i) {
                                accounts[i]->bAccMgrUIChanged = FALSE;
                                if (accounts[i]->hwndAccMgrUI) {
                                        DestroyWindow(accounts[i]->hwndAccMgrUI);
                                        accounts[i]->hwndAccMgrUI = NULL;
                }       }       }

                Window_FreeIcon_IcoLib( hwndDlg );
                Button_FreeIcon_IcoLib( hwndDlg, IDC_ADD );
                Button_FreeIcon_IcoLib( hwndDlg, IDC_EDIT );
                Button_FreeIcon_IcoLib( hwndDlg, IDC_REMOVE );
                Button_FreeIcon_IcoLib( hwndDlg, IDC_OPTIONS );
                Button_FreeIcon_IcoLib( hwndDlg, IDC_UPGRADE );
                Utils_SaveWindowPosition( hwndDlg, NULL, "AccMgr", "");
                sttSubclassAccList(GetDlgItem(hwndDlg, IDC_ACCLIST), FALSE);
                DeleteObject(dat->hfntTitle);
                DeleteObject(dat->hfntText);
                mir_free(dat);
                hAccMgr = NULL;
                break;
        }

        return FALSE;
}

static INT_PTR OptProtosShow(WPARAM, LPARAM)
{
        if ( !hAccMgr )
                hAccMgr = CreateDialogParam( hMirandaInst, MAKEINTRESOURCE(IDD_ACCMGR), NULL, AccMgrDlgProc, 0 );

        ShowWindow( hAccMgr, SW_RESTORE );
        SetForegroundWindow( hAccMgr );
        SetActiveWindow( hAccMgr );
        return 0;
}

int OptProtosLoaded(WPARAM, LPARAM)
{
        CLISTMENUITEM mi = { 0 };
        mi.cbSize = sizeof(mi);
        mi.flags = CMIF_ICONFROMICOLIB;
        mi.icolibItem = GetSkinIconHandle( SKINICON_OTHER_ACCMGR );
        mi.position = 1900000000;
        mi.pszName = LPGEN("&Accounts...");
        mi.pszService = MS_PROTO_SHOWACCMGR;
        CallService( MS_CLIST_ADDMAINMENUITEM, 0, ( LPARAM )&mi );
        return 0;
}

static int OnAccListChanged( WPARAM eventCode, LPARAM lParam )
{
        PROTOACCOUNT* pa = (PROTOACCOUNT*)lParam;

        switch( eventCode ) {
        case PRAC_CHANGED:
                if ( pa->ppro ) {
                        mir_free( pa->ppro->m_tszUserName );
                        pa->ppro->m_tszUserName = mir_tstrdup( pa->tszAccountName );
                        pa->ppro->OnEvent( EV_PROTO_ONRENAME, 0, lParam );
                }
        }

        return 0;
}

static int ShutdownAccMgr(WPARAM, LPARAM)
{
        if ( IsWindow( hAccMgr ))
                DestroyWindow( hAccMgr );
        hAccMgr = NULL;
        return 0;
}

int LoadProtoOptions( void )
{
        CreateServiceFunction( MS_PROTO_SHOWACCMGR, OptProtosShow );

        HookEvent( ME_SYSTEM_MODULESLOADED, OptProtosLoaded );
        HookEvent( ME_PROTO_ACCLISTCHANGED, OnAccListChanged );
        HookEvent( ME_SYSTEM_PRESHUTDOWN, ShutdownAccMgr );
        return 0;
}

